added Feb 2001 SDK
[windows-sources.git] / shared source / sscli20 / jscript / engine / try.cs
blob8e7d7469aeb6678999f586f5c78be3aa6f2e2a1d
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 namespace Microsoft.JScript {
18 using Microsoft.JScript.Vsa;
19 using System;
20 using System.Collections;
21 using System.Reflection;
22 using System.Reflection.Emit;
24 public sealed class Try : AST{
25 private AST body;
26 private TypeExpression type;
27 private AST handler;
28 private AST finally_block;
29 private BlockScope handler_scope;
30 private FieldInfo field;
31 private String fieldName;
32 private bool finallyHasControlFlowOutOfIt;
33 private Context tryEndContext;
35 internal Try(Context context, AST body, AST identifier, TypeExpression type, AST handler, AST finally_block, bool finallyHasControlFlowOutOfIt, Context tryEndContext)
36 : base(context) {
37 this.body = body;
38 this.type = type;
39 this.handler = handler;
40 this.finally_block = finally_block;
41 ScriptObject current_scope = (ScriptObject)Globals.ScopeStack.Peek();
42 while (current_scope is WithObject) //Can only happen at run time and only if there is an eval
43 current_scope = current_scope.GetParent();
44 this.handler_scope = null;
45 this.field = null;
46 if (identifier != null){
47 this.fieldName = identifier.ToString();
48 this.field = current_scope.GetField(this.fieldName, BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static);
49 if (this.field != null){
50 if (type == null && (field is JSVariableField && field.IsStatic && ((JSVariableField)field).type == null) && !field.IsLiteral && !field.IsInitOnly)
51 return; //preserve legacy semantics by using the existing variable
52 if (((IActivationObject)current_scope).GetLocalField(this.fieldName) != null)
53 identifier.context.HandleError(JSError.DuplicateName, false);
55 this.handler_scope = new BlockScope(current_scope);
56 this.handler_scope.catchHanderScope = true;
57 JSVariableField f = this.handler_scope.AddNewField(identifier.ToString(), Missing.Value, FieldAttributes.Public); // must be a local
58 this.field = f; f.originalContext = identifier.context;
59 if (identifier.context.document.debugOn && this.field is JSLocalField){
60 this.handler_scope.AddFieldForLocalScopeDebugInfo((JSLocalField)this.field);
63 this.finallyHasControlFlowOutOfIt = finallyHasControlFlowOutOfIt;
64 this.tryEndContext = tryEndContext;
67 internal override Object Evaluate(){
68 int i = Globals.ScopeStack.Size();
69 int j = Globals.CallContextStack.Size();
70 Completion bc = null;
71 Completion fc = null;
72 try{
73 Object eValue = null;
74 try{
75 bc = (Completion)this.body.Evaluate();
76 }catch(Exception e){
77 if (this.handler == null) throw;
78 eValue = e;
79 if (this.type != null){
80 Type ht = this.type.ToType();
81 if (Typeob.Exception.IsAssignableFrom(ht)){
82 if (!ht.IsInstanceOfType(e)) throw;
83 }else if (!ht.IsInstanceOfType(eValue = JScriptExceptionValue(e, this.Engine)))
84 throw;
85 }else
86 eValue = JScriptExceptionValue(e, this.Engine);
87 }catch{
88 eValue = new JScriptException(JSError.NonClsException);
91 if (eValue != null) {
92 Globals.ScopeStack.TrimToSize(i);
93 Globals.CallContextStack.TrimToSize(j);
94 if (this.handler_scope != null){
95 this.handler_scope.SetParent(Globals.ScopeStack.Peek());
96 Globals.ScopeStack.Push(this.handler_scope);
98 if (this.field != null)
99 this.field.SetValue(Globals.ScopeStack.Peek(), eValue);
100 bc = (Completion)this.handler.Evaluate();
102 }finally{
103 Globals.ScopeStack.TrimToSize(i);
104 Globals.CallContextStack.TrimToSize(j);
105 if (this.finally_block != null){
106 fc = (Completion)this.finally_block.Evaluate();
109 if (bc == null || fc != null && (fc.Exit > 0 || fc.Continue > 0 || fc.Return))
110 bc = fc;
111 else{
112 if (fc != null && fc.value is Missing)
113 bc.value = fc.value;
115 Completion result = new Completion();
116 result.Continue = bc.Continue - 1;
117 result.Exit = bc.Exit - 1;
118 result.Return = bc.Return;
119 result.value = bc.value;
120 return result;
123 internal override Context GetFirstExecutableContext(){
124 return this.body.GetFirstExecutableContext();
127 public static Object JScriptExceptionValue(Object e, VsaEngine engine){
128 if (engine == null){
129 engine = new VsaEngine(true);
130 engine.InitVsaEngine("JS7://Microsoft.JScript.Vsa.VsaEngine", new DefaultVsaSite());
132 ErrorConstructor originalError = engine.Globals.globalObject.originalError;
133 if (e is JScriptException){
134 Object value = ((JScriptException)e).value;
135 if (value is Exception || value is Missing || (((JScriptException)e).Number&0xFFFF) != (int)JSError.UncaughtException)
136 return originalError.Construct((Exception)e);
137 return value; //The exception wraps a non-exception value
138 }else if (e is StackOverflowException)
139 return originalError.Construct(new JScriptException(JSError.OutOfStack));
140 else if (e is OutOfMemoryException)
141 return originalError.Construct(new JScriptException(JSError.OutOfMemory));
142 return originalError.Construct(e);
145 internal override AST PartiallyEvaluate(){
146 if (this.type != null){
147 this.type.PartiallyEvaluate();
148 ((JSVariableField)this.field).type = type;
149 }else if (this.field is JSLocalField)
150 ((JSLocalField)this.field).SetInferredType(Typeob.Object, null); //This should never give an error
151 ScriptObject current_scope = Globals.ScopeStack.Peek();
152 while (current_scope is WithObject) current_scope = current_scope.GetParent();
153 FunctionScope scope = null;
154 BitArray before = null;
155 if (current_scope is FunctionScope){
156 scope = (FunctionScope)current_scope;
157 before = scope.DefinedFlags;
159 this.body = this.body.PartiallyEvaluate();
160 if (this.handler != null){
161 if (this.handler_scope != null)
162 Globals.ScopeStack.Push(this.handler_scope);
163 if (this.field is JSLocalField)
164 ((JSLocalField)this.field).isDefined = true;
165 this.handler = this.handler.PartiallyEvaluate();
166 if (this.handler_scope != null)
167 Globals.ScopeStack.Pop();
169 if (this.finally_block != null)
170 this.finally_block = this.finally_block.PartiallyEvaluate();
171 if (scope != null)
172 scope.DefinedFlags = before;
173 return this;
176 public static void PushHandlerScope(VsaEngine engine, String id, int scopeId){
177 engine.PushScriptObject(new BlockScope(engine.ScriptObjectStackTop(), id, scopeId));
180 internal override void TranslateToIL(ILGenerator il, Type rtype){
181 //This assumes that rtype == Void.class.
182 bool savedInsideProtectedRegion = compilerGlobals.InsideProtectedRegion;
183 compilerGlobals.InsideProtectedRegion = true;
184 compilerGlobals.BreakLabelStack.Push(compilerGlobals.BreakLabelStack.Peek(0));
185 compilerGlobals.ContinueLabelStack.Push(compilerGlobals.ContinueLabelStack.Peek(0));
186 il.BeginExceptionBlock();
187 if (this.finally_block != null){
188 if (this.finallyHasControlFlowOutOfIt)
189 il.BeginExceptionBlock();
190 if (this.handler != null)
191 il.BeginExceptionBlock();
193 this.body.TranslateToIL(il, Typeob.Void);
194 if (this.tryEndContext != null)
195 this.tryEndContext.EmitLineInfo(il);
196 if (this.handler != null){
197 if (this.type == null){
198 il.BeginCatchBlock(Typeob.Exception);
199 this.handler.context.EmitLineInfo(il);
200 this.EmitILToLoadEngine(il);
201 il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
202 }else{
203 Type filterType = this.type.ToType();
204 if (Typeob.Exception.IsAssignableFrom(filterType)){
205 il.BeginCatchBlock(filterType);
206 this.handler.context.EmitLineInfo(il);
208 else{
209 il.BeginExceptFilterBlock();
210 this.handler.context.EmitLineInfo(il);
211 this.EmitILToLoadEngine(il);
212 il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
213 il.Emit(OpCodes.Isinst, filterType);
214 il.Emit(OpCodes.Ldnull);
215 il.Emit(OpCodes.Cgt_Un);
216 il.BeginCatchBlock(null);
217 this.EmitILToLoadEngine(il);
218 il.Emit(OpCodes.Call, CompilerGlobals.jScriptExceptionValueMethod);
219 Convert.Emit(this, il, Typeob.Object, filterType);
222 Object tok = this.field is JSVariableField ? ((JSVariableField)this.field).GetMetaData() : this.field;
223 if (tok is LocalBuilder)
224 il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
225 else if (tok is FieldInfo)
226 il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
227 else
228 Convert.EmitLdarg(il, (short)tok);
230 if (this.handler_scope != null){
231 if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func
232 this.EmitILToLoadEngine(il);
233 il.Emit(OpCodes.Ldstr, this.fieldName);
234 ConstantWrapper.TranslateToILInt(il, this.handler_scope.scopeId);
235 il.Emit(OpCodes.Call, Typeob.Try.GetMethod("PushHandlerScope"));
236 Globals.ScopeStack.Push(this.handler_scope);
237 il.BeginExceptionBlock();
239 il.BeginScope(); // so that we can emit local scoped information for the handler variable
240 if (this.context.document.debugOn)
241 this.handler_scope.EmitLocalInfoForFields(il);
243 this.handler.TranslateToIL(il, Typeob.Void);
244 if (this.handler_scope != null){
245 il.EndScope();
246 if (!this.handler_scope.isKnownAtCompileTime){ //I.e. eval or nested func
247 il.BeginFinallyBlock();
248 this.EmitILToLoadEngine(il);
249 il.Emit(OpCodes.Call, CompilerGlobals.popScriptObjectMethod);
250 il.Emit(OpCodes.Pop);
251 Globals.ScopeStack.Pop();
252 il.EndExceptionBlock();
255 il.EndExceptionBlock();
257 if (this.finally_block != null){
258 bool savedInsideFinally = compilerGlobals.InsideFinally;
259 int savedFinallyStackTop = compilerGlobals.FinallyStackTop;
260 compilerGlobals.InsideFinally = true;
261 compilerGlobals.FinallyStackTop = compilerGlobals.BreakLabelStack.Size();
262 il.BeginFinallyBlock();
263 this.finally_block.TranslateToIL(il, Typeob.Void);
264 il.EndExceptionBlock();
265 compilerGlobals.InsideFinally = savedInsideFinally;
266 compilerGlobals.FinallyStackTop = savedFinallyStackTop;
267 if (this.finallyHasControlFlowOutOfIt){
268 il.BeginCatchBlock(Typeob.BreakOutOfFinally);
269 il.Emit(OpCodes.Ldfld, Typeob.BreakOutOfFinally.GetField("target"));
270 // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body)
271 // and that would generate a JIT assert because the jump is sometimes outside the function
272 for (int i = compilerGlobals.BreakLabelStack.Size()-1, n = i; i > 0; i--){
273 il.Emit(OpCodes.Dup);
274 ConstantWrapper.TranslateToILInt(il, i);
275 Label lab = il.DefineLabel();
276 il.Emit(OpCodes.Blt_S, lab);
277 il.Emit(OpCodes.Pop);
278 if (savedInsideFinally && i < savedFinallyStackTop)
279 il.Emit(OpCodes.Rethrow);
280 else
281 il.Emit(OpCodes.Leave, (Label)compilerGlobals.BreakLabelStack.Peek(n-i));
282 il.MarkLabel(lab);
284 il.Emit(OpCodes.Pop);
285 il.BeginCatchBlock(Typeob.ContinueOutOfFinally);
286 il.Emit(OpCodes.Ldfld, Typeob.ContinueOutOfFinally.GetField("target"));
287 // don't need to go to 0 in the loop because 0 is the outmost block (i.e. function body)
288 for (int i = compilerGlobals.ContinueLabelStack.Size()-1, n = i; i > 0; i--){
289 il.Emit(OpCodes.Dup);
290 ConstantWrapper.TranslateToILInt(il, i);
291 Label lab = il.DefineLabel();
292 il.Emit(OpCodes.Blt_S, lab);
293 il.Emit(OpCodes.Pop);
294 if (savedInsideFinally && i < savedFinallyStackTop)
295 il.Emit(OpCodes.Rethrow);
296 else
297 il.Emit(OpCodes.Leave, (Label)compilerGlobals.ContinueLabelStack.Peek(n-i));
298 il.MarkLabel(lab);
300 il.Emit(OpCodes.Pop);
301 ScriptObject scope = Globals.ScopeStack.Peek();
302 while (scope != null && !(scope is FunctionScope))
303 scope = scope.GetParent();
304 if (scope != null && !savedInsideFinally){
305 il.BeginCatchBlock(Typeob.ReturnOutOfFinally);
306 il.Emit(OpCodes.Pop);
307 il.Emit(OpCodes.Leave, ((FunctionScope)scope).owner.returnLabel);
309 il.EndExceptionBlock();
312 compilerGlobals.InsideProtectedRegion = savedInsideProtectedRegion;
313 compilerGlobals.BreakLabelStack.Pop();
314 compilerGlobals.ContinueLabelStack.Pop();
317 internal override void TranslateToILInitializer(ILGenerator il){
318 this.body.TranslateToILInitializer(il);
319 if (this.handler != null)
320 this.handler.TranslateToILInitializer(il);
321 if (this.finally_block != null)
322 this.finally_block.TranslateToILInitializer(il);